package com.zby.ss.core.factoryimpl;

import com.zby.ss.core.builder.ClassBuilder;
import com.zby.ss.core.facotry.ObjectFactory;
import com.zby.ss.core.util.FieldHelper;
import com.zby.ss.core.util.MethodHelper;
import com.zby.ss.util.ArrayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;

/**
 * Created By zby on 15:42 2019/2/16
 */

public class ObjectFactoryImpl<T> implements ObjectFactory<T> {

    private Logger logger = LoggerFactory.getLogger(ObjectFactory.class);

    @Override
    public T creatObjectByConstruct(String classPath) {
        return creatObjectByConstruct(ClassBuilder.<T>classPathToClazz(classPath));
    }

    @Override
    public T creatObjectByConstruct(Class<T> clazz) {
        if (null == clazz)
            return null;
        try {
            Field[] fields = clazz.getDeclaredFields();
            if (ArrayUtil.isEmpty(fields)) {
                return clazz.getConstructor().newInstance();
            }
            Class<?>[] paramType = new Class[fields.length];
            Object[] objects = new Object[fields.length];
            for (int i = 0; i < fields.length; i++) {
                Class<?> tmp = fields[i].getType();
                paramType[i] = tmp;
                fields[i].setAccessible(true);
                //属性对象,应该创建子类对象
                objects[i] = tmp.newInstance();
            }
            return clazz.getConstructor(paramType).newInstance(objects);
        } catch (SecurityException e) {
            logger.error("获取类" + clazz.getSimpleName() + "私有属性异常");
            e.printStackTrace();
        } catch (InstantiationException e) {
            logger.error("初始化类" + clazz.getSimpleName() + "失败");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public T creatObjectByProperty(String classPath) {
        return creatObjectByProperty(ClassBuilder.<T>classPathToClazz(classPath));
    }

    @Override
    public T creatObjectByProperty(Class<T> clazz) {
        if (null == clazz)
            return null;
        Class<?> superClass = clazz.getSuperclass();
        Class consParamType = null;
        Object property = null;
        String methodName = null;
        T t = null;
        if (superClass != null) {
            try {
                //根据单一的构造器比如，
                // public OrderSnapshotServiceImpl(OrderSnapshotDaoImpl orderSnapshotDao) {
                //        super(orderSnapshotDao);
                // }
                // 首先获取构造器，然后获取构造器的参数
                // 获取参数类型，先将参数类型的实例化
                // 再将参数实例化的对象引用赋值给新参，就像是构造器创造对象
                Constructor<T>[] constructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
                ArrayUtil.validateArray(clazz, constructors);
                Parameter[] parameters = constructors[0].getParameters();
                ArrayUtil.validateArray(clazz, parameters);
                consParamType = parameters[0].getType();
                property = consParamType.newInstance();
                t = constructors[0].newInstance(property);

                //获取属相，通过属性方法创造对象
                Field[] fields = clazz.getDeclaredFields();
                if (FieldHelper.isNotEmpty(fields)) {
                    for (Field field : fields) {
                        Class propType = field.getType();
                        methodName = MethodHelper.propsToSetMethod(field.getName(), propType);
                        Method method = clazz.getMethod(methodName, propType);
                        method.setAccessible(true);
                        //如果属性和构造器的类型相同，则直接用构造器的对象，不再重新创建
                        if (!consParamType.getSimpleName().equals(propType.getSimpleName())) {
                            property = propType.newInstance();
                        }
                        method.invoke(t, property);
                    }
                }
                return t;
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                logger.error("获取类" + clazz.getSimpleName() + "私有属性异常");
                e.printStackTrace();
            } catch (InstantiationException e) {
                logger.error("初始化类" + clazz.getSimpleName() + "失败");
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                logger.error("类" + clazz.getName() + "没有" + methodName + "方法");
                e.printStackTrace();
            }
        }
        return null;
    }
}
